{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 17634,
     "status": "ok",
     "timestamp": 1649956504817,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "Q0_qiuMECqjn",
    "outputId": "e923fc32-68ab-48ba-97ca-2e169458759b"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Iteration 0:   0%|                                                                              | 0/25 [00:00<?, ?it/s]C:\\Users\\10696\\AppData\\Local\\Temp\\ipykernel_7672\\1223747720.py:57: UserWarning: Creating a tensor from a list of numpy.ndarrays is extremely slow. Please consider converting the list to a single numpy.ndarray with numpy.array() before converting to a tensor. (Triggered internally at ..\\torch\\csrc\\utils\\tensor_new.cpp:248.)\n",
      "  state = torch.tensor([state], dtype=torch.float).to(self.device)\n",
      "Iteration 0: 100%|██████████████████████████████████████████| 25/25 [00:02<00:00,  9.07it/s, episode=20, return=54.700]\n",
      "Iteration 1: 100%|█████████████████████████████████████████| 25/25 [00:15<00:00,  1.64it/s, episode=45, return=163.700]\n",
      "Iteration 2: 100%|█████████████████████████████████████████| 25/25 [00:19<00:00,  1.31it/s, episode=70, return=235.400]\n",
      "Iteration 3: 100%|█████████████████████████████████████████| 25/25 [00:12<00:00,  1.97it/s, episode=95, return=269.700]\n",
      "Iteration 4: 100%|████████████████████████████████████████| 25/25 [00:16<00:00,  1.50it/s, episode=120, return=463.500]\n",
      "Iteration 5: 100%|████████████████████████████████████████| 25/25 [00:21<00:00,  1.15it/s, episode=145, return=437.500]\n",
      "Iteration 6: 100%|████████████████████████████████████████| 25/25 [00:33<00:00,  1.33s/it, episode=170, return=500.000]\n",
      "Iteration 7: 100%|████████████████████████████████████████| 25/25 [00:30<00:00,  1.23s/it, episode=195, return=500.000]\n",
      "Iteration 8: 100%|████████████████████████████████████████| 25/25 [00:21<00:00,  1.16it/s, episode=220, return=425.200]\n",
      "Iteration 9: 100%|████████████████████████████████████████| 25/25 [00:26<00:00,  1.05s/it, episode=245, return=383.300]\n"
     ]
    }
   ],
   "source": [
    "import gymnasium as gym\n",
    "import torch\n",
    "import torch.nn.functional as F\n",
    "import torch.nn as nn\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from tqdm import tqdm\n",
    "import random\n",
    "import rl_utils\n",
    "from tqdm import tqdm\n",
    "import imageio\n",
    "\n",
    "## 构造智能体 agent 的大脑，也就是输入状态，返回该状态下，选择每个动作的概率\n",
    "## 输入是状态的，也就是 (车子center-point的坐标，车子的速度，杆的竖直角度，杆的角速度)\n",
    "## 返回值应该是2 dim\n",
    "class PolicyNet(torch.nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim):\n",
    "        super(PolicyNet, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, action_dim)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return F.softmax(self.fc2(x), dim=1)  ## 返回该状态下，选择的动作的概率\n",
    "\n",
    "## 构造智能体 agent 的大脑，也就是输入状态，返回该状态下，每个动作的动作价值\n",
    "## 输入是状态的，也就是 (车子center-point的坐标，车子的速度，杆的竖直角度，杆的角速度)\n",
    "## 返回值应该是2 dim\n",
    "class ValueNet(torch.nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim):\n",
    "        super(ValueNet, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.fc1(x))\n",
    "        return self.fc2(x)\n",
    "\n",
    "## 首先使用强化学习算法 PPO 来训练专家策略，然后用来采样的，产生专家数据\n",
    "class PPO:\n",
    "    ''' PPO算法,采用截断方式 '''\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim, actor_lr, critic_lr,\n",
    "                 lmbda, epochs, eps, gamma, device):\n",
    "        self.actor = PolicyNet(state_dim, hidden_dim, action_dim).to(device)  ##  策略网络的\n",
    "        self.critic = ValueNet(state_dim, hidden_dim).to(device)  ##  价值网络\n",
    "        self.actor_optimizer = torch.optim.Adam(self.actor.parameters(),\n",
    "                                                lr=actor_lr)  ##  函数配置优化器\n",
    "        self.critic_optimizer = torch.optim.Adam(self.critic.parameters(),\n",
    "                                                 lr=critic_lr)  ##  价值函数配置优化器\n",
    "        self.gamma = gamma   ## 衰减因子的呢\n",
    "        self.lmbda = lmbda\n",
    "        self.epochs = epochs  # 一条序列的数据用于训练轮数\n",
    "        self.eps = eps  # PPO中截断范围的参数\n",
    "        self.device = device\n",
    "\n",
    "    def take_action(self, state):            # 根据动作概率分布随机采样\n",
    "        state = torch.tensor([state], dtype=torch.float).to(self.device)\n",
    "        probs = self.actor(state)       ## 拿到该状态下，每个动作的选择概率\n",
    "        action_dist = torch.distributions.Categorical(probs)    ##   配置 好采样的概率\n",
    "        action = action_dist.sample()        ## 对该状态下，所有的动作采样，采样的概率是probs\n",
    "        return action.item()                 ## 返回依概率采样得到的动作\n",
    "\n",
    "    def update(self, transition_dict):\n",
    "        ## 拿到这条序列内的 奖励、状态和动作，下一个状态、是否完成的\n",
    "        states = torch.tensor(transition_dict['states'],\n",
    "                              dtype=torch.float).to(self.device)\n",
    "        actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(\n",
    "            self.device)\n",
    "        rewards = torch.tensor(transition_dict['rewards'],\n",
    "                               dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        next_states = torch.tensor(transition_dict['next_states'],\n",
    "                                   dtype=torch.float).to(self.device)\n",
    "        dones = torch.tensor(transition_dict['dones'],\n",
    "                             dtype=torch.float).view(-1, 1).to(self.device)\n",
    "        ## 用下个状态求下一个状态的状态动作价值，然后间接求出当前状态的状态动作价值\n",
    "        td_target = rewards + self.gamma * self.critic(next_states) * (1 -\n",
    "                                                                       dones)\n",
    "        ## 间接求出的价值 - 直接求出的当前状态的状态动作价值，也就是 TD-error，或者是优势函数 A\n",
    "        td_delta = td_target - self.critic(states)\n",
    "        ##  算出优势函数，广义优势估计，也就是每一步优势的均值\n",
    "        advantage = rl_utils.compute_advantage(self.gamma, self.lmbda,\n",
    "                                               td_delta.cpu()).to(self.device)\n",
    "        ## 选择的旧动作概率的log值，不反向传播求梯度，detach\n",
    "        old_log_probs = torch.log(self.actor(states).gather(1,\n",
    "                                                            actions)).detach()\n",
    "\n",
    "        for _ in range(self.epochs):\n",
    "            ## 选择的动作概率的log值，不反向传播求梯度，detach\n",
    "            log_probs = torch.log(self.actor(states).gather(1, actions))\n",
    "            ratio = torch.exp(log_probs - old_log_probs)   ## 算重要性采样\n",
    "            surr1 = ratio * advantage ## 重要性采样和优势估计相乘的\n",
    "            surr2 = torch.clamp(ratio, 1 - self.eps,\n",
    "                                1 + self.eps) * advantage  # 截断\n",
    "            actor_loss = torch.mean(-torch.min(surr1, surr2))  # PPO损失函数\n",
    "            ## 直接求出当前状态的状态动作价值，和 间接求出的价值，使用 MSE 来算损失函数的，td_target不反向传播求梯度，detach\n",
    "            critic_loss = torch.mean(\n",
    "                F.mse_loss(self.critic(states), td_target.detach()))\n",
    "            self.actor_optimizer.zero_grad()\n",
    "            self.critic_optimizer.zero_grad()  ## 价值网络的参数梯度置零的\n",
    "            actor_loss.backward()\n",
    "            critic_loss.backward()   ## 价值网络的损失loss反向传播梯度\n",
    "            self.actor_optimizer.step()\n",
    "            self.critic_optimizer.step()   # 更新价值函数\n",
    "\n",
    "actor_lr = 1e-3\n",
    "critic_lr = 1e-2\n",
    "num_episodes = 250\n",
    "hidden_dim = 128\n",
    "gamma = 0.98\n",
    "lmbda = 0.95\n",
    "epochs = 10\n",
    "eps = 0.2\n",
    "device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\n",
    "    \"cpu\")\n",
    "\n",
    "env_name = 'CartPole-v1'\n",
    "env = gym.make(env_name, render_mode=\"rgb_array\")\n",
    "_ = env.reset(seed=0)\n",
    "torch.manual_seed(0)\n",
    "state_dim = env.observation_space.shape[0]\n",
    "action_dim = env.action_space.n\n",
    "ppo_agent = PPO(state_dim, hidden_dim, action_dim, actor_lr, critic_lr, lmbda,\n",
    "                epochs, eps, gamma, device)\n",
    "## 使用 PPO 来训练专家策略的\n",
    "return_list = rl_utils.train_on_policy_agent(env, ppo_agent, num_episodes)\n",
    "\n",
    "# Iteration 0: 100%|██████████| 25/25 [00:00<00:00, 32.56it/s, episode=20,\n",
    "# return=40.700]\n",
    "# Iteration 1: 100%|██████████| 25/25 [00:09<00:00,  2.75it/s, episode=45,\n",
    "# return=182.800]\n",
    "# Iteration 2: 100%|██████████| 25/25 [00:11<00:00,  2.27it/s, episode=70,\n",
    "# return=176.100]\n",
    "# Iteration 3: 100%|██████████| 25/25 [00:11<00:00,  2.16it/s, episode=95,\n",
    "# return=194.500]\n",
    "# Iteration 4: 100%|██████████| 25/25 [00:11<00:00,  2.08it/s, episode=120,\n",
    "# return=180.600]\n",
    "# Iteration 5: 100%|██████████| 25/25 [00:12<00:00,  2.03it/s, episode=145,\n",
    "# return=200.000]\n",
    "# Iteration 6: 100%|██████████| 25/25 [00:11<00:00,  2.08it/s, episode=170,\n",
    "# return=185.700]\n",
    "# Iteration 7: 100%|██████████| 25/25 [00:11<00:00,  2.14it/s, episode=195,\n",
    "# return=200.000]\n",
    "# Iteration 8: 100%|██████████| 25/25 [00:12<00:00,  2.05it/s, episode=220,\n",
    "# return=200.000]\n",
    "# Iteration 9: 100%|██████████| 25/25 [00:11<00:00,  2.27it/s, episode=245,\n",
    "# return=196.900]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "executionInfo": {
     "elapsed": 524,
     "status": "ok",
     "timestamp": 1649956505337,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "HsyfI_zoCqjq"
   },
   "outputs": [],
   "source": [
    "## 使用专家策略模型，只采样1个序列，每个序列采样30个状态动作对\n",
    "def sample_expert_data(n_episode):\n",
    "    states = []\n",
    "    actions = []\n",
    "    for episode in range(n_episode):         ## 1个序列\n",
    "        state = env.reset()      ## 环境重置的\n",
    "        if len(state)!=2*2:\n",
    "            state = state[0]\n",
    "        done = False  ## 是否已经完成\n",
    "        while not done:\n",
    "            action = ppo_agent.take_action(state)  ## 策略根据状态给出动作\n",
    "            states.append(state)\n",
    "            actions.append(action)\n",
    "            ##  环境执行动作，并反馈下一个状态、动作的奖励、是否完成、步长太长的，info\n",
    "            next_state, reward, terminated, truncated, info = env.step(action)\n",
    "            done = terminated | truncated       ## 终止或者步长太长，都会导致已经结束\n",
    "            # next_state, reward, done, _ = env.step(action)   ## 环境执行动作，并给出下一个状态、动作\n",
    "            state = next_state\n",
    "    return np.array(states), np.array(actions)  ## 分别返回状态和动作对\n",
    "\n",
    "\n",
    "_ = env.reset(seed=0)\n",
    "torch.manual_seed(0)\n",
    "random.seed(0)\n",
    "n_episode = 1\n",
    "expert_s, expert_a = sample_expert_data(n_episode)\n",
    "\n",
    "n_samples = 30  # 采样30个数据\n",
    "random_index = random.sample(range(expert_s.shape[0]), n_samples)   ## 从状态动作对内继续采样\n",
    "expert_s = expert_s[random_index]\n",
    "expert_a = expert_a[random_index]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 184885,
     "status": "ok",
     "timestamp": 1649956690218,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "QLLD1U-1Cqjr",
    "outputId": "173897ed-3262-4a90-c2c2-ff125678f624"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "进度条: 100%|████████████████████████████████████████████████████████| 1000/1000 [01:43<00:00,  9.64it/s, return=9.440]\n"
     ]
    }
   ],
   "source": [
    "## 模仿者智能体\n",
    "class BehaviorClone:\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim, lr):\n",
    "        self.policy = PolicyNet(state_dim, hidden_dim, action_dim).to(device)  ## 策略网络的\n",
    "        self.optimizer = torch.optim.Adam(self.policy.parameters(), lr=lr)  ## 优化器\n",
    "\n",
    "    ## 使用专家采样数据，模仿者学着靠拢专家策略\n",
    "    def learn(self, states, actions):\n",
    "        states = torch.tensor(states, dtype=torch.float).to(device)  ## 输入\n",
    "        actions = torch.tensor(actions).view(-1, 1).long().to(device)  ## 输出，也就是监督学习的 truth label\n",
    "        ## 拿到策略网络输出指定动作的概率的log值\n",
    "        log_probs = torch.log(self.policy(states).gather(1, actions))\n",
    "        ## 最小化 (最大似然估计值的相反数)，也就是 最大化 最大似然估计值\n",
    "        bc_loss = torch.mean(-log_probs)  # 最大似然估计\n",
    "\n",
    "        self.optimizer.zero_grad() ## 梯度置0\n",
    "        bc_loss.backward() ## 反向传播求出参数梯度\n",
    "        self.optimizer.step()  ##  使用梯度来update参数\n",
    "\n",
    "    ## 模仿者采取动作，并按照概率给出采样的动作\n",
    "    def take_action(self, state):\n",
    "        state = torch.tensor([state], dtype=torch.float).to(device)\n",
    "        probs = self.policy(state)\n",
    "        action_dist = torch.distributions.Categorical(probs)\n",
    "        action = action_dist.sample()\n",
    "        return action.item()\n",
    "\n",
    "def test_agent(agent, env, n_episode):\n",
    "    return_list = []\n",
    "    for episode in range(n_episode):\n",
    "        episode_return = 0\n",
    "        state = env.reset()\n",
    "        if len(state)!=2*2:\n",
    "            state = state[0]\n",
    "        done = False\n",
    "        while not done:\n",
    "            action = agent.take_action(state)\n",
    "            ##  环境执行动作，并反馈下一个状态、动作的奖励、是否完成、步长太长的，info\n",
    "            next_state, reward, terminated, truncated, info = env.step(action)\n",
    "            done = terminated | truncated       ## 终止或者步长太长，都会导致已经结束\n",
    "            # next_state, reward, done, _ = env.step(action)\n",
    "            state = next_state\n",
    "            episode_return += reward\n",
    "        return_list.append(episode_return)\n",
    "    return np.mean(return_list)\n",
    "\n",
    "_ = env.reset(seed=6)\n",
    "torch.manual_seed(6)\n",
    "np.random.seed(6)\n",
    "\n",
    "lr = 1e-3\n",
    "bc_agent = BehaviorClone(state_dim, hidden_dim, action_dim, lr)\n",
    "n_iterations = 1000\n",
    "batch_size = 64\n",
    "test_returns = []\n",
    "\n",
    "## 行为克隆的\n",
    "with tqdm(total=n_iterations, desc=\"进度条\") as pbar:\n",
    "    for i in range(n_iterations):\n",
    "        sample_indices = np.random.randint(low=0,\n",
    "                                           high=expert_s.shape[0],\n",
    "                                           size=batch_size)\n",
    "        bc_agent.learn(expert_s[sample_indices], expert_a[sample_indices]) ## 模仿者使用专家数据来train\n",
    "        current_return = test_agent(bc_agent, env, 5) ## 模仿者测验结果\n",
    "        test_returns.append(current_return)\n",
    "        if (i + 1) % 10 == 0:\n",
    "            pbar.set_postfix({'return': '%.3f' % np.mean(test_returns[-10:])})\n",
    "        pbar.update(1)\n",
    "\n",
    "# 进度条: 100%|██████████| 1000/1000 [00:50<00:00, 19.82it/s, return=42.000]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 295
    },
    "executionInfo": {
     "elapsed": 22,
     "status": "ok",
     "timestamp": 1649956690807,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "RWdMQsYkCqjr",
    "outputId": "d235f1c4-a237-4763-852d-30f1b677a397"
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjIAAAHHCAYAAACle7JuAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB/5klEQVR4nO3dd3wU1doH8N/uppKQhAApQCD0IlVADAiioAiIKNiwgaJevOAVu3gV9b4qqBdFuYodbFhQEEVEKQKidKT3jkBCCamk7p73j7Cbmd2Z2ZntG37f++GazM7OnJ0kO88+5znnmIQQAkRERERhyBzsBhARERF5ioEMERERhS0GMkRERBS2GMgQERFR2GIgQ0RERGGLgQwRERGFLQYyREREFLYYyBAREVHYYiBDREREYYuBDBGRj5hMJjz//PPBbgbRBYWBDFGImjlzJkwmk+xfSkoKrrjiCvz888+Kz8nJycFjjz2GNm3aoFatWoiLi0PXrl3x4osvIi8vL7AvwI1ly5Zh2LBhSEtLQ1RUFFJSUjBkyBDMmTPHp+c5fvw4nn/+eWzatMnlsVGjRsmub0JCAjp16oQpU6agrKzMp+3wp19//RWjR49G+/btYbFYkJmZGewmEQVMRLAbQETa/vOf/6Bp06YQQiAnJwczZ87EoEGD8OOPP+Laa6917Ldu3ToMGjQIRUVFuOOOO9C1a1cAwPr16zF58mSsWLECv/76a7Behsxzzz2H//znP2jZsiX+8Y9/oEmTJjhz5gwWLFiA4cOH44svvsBtt93mk3MdP34cL7zwAjIzM9G5c2eXx6Ojo/Hhhx8CAPLy8vDdd9/hsccew7p16/DVV1/5pA3+NmvWLHz99de4+OKL0aBBg2A3hyiwBBGFpBkzZggAYt26dbLtubm5IjIyUtx2222ObWfPnhUNGzYUqampYufOnS7Hys7OFv/3f//n9zbrMXv2bAFA3HjjjaK8vNzl8YULF4off/zR6/NUVFSIsrIysW7dOgFAzJgxw2WfkSNHiri4ONk2q9UqunXrJgCIY8eOGTonAPHcc8950WrPHDt2zHEtBw8eLJo0aRLwNhAFC7uWiMJMUlISYmNjERFRnVB97733cOzYMbz++uto06aNy3NSU1PxzDPPuD320qVL0bt3b8TFxSEpKQlDhw7Fzp07Zfs8//zzMJlM2LdvH0aNGoWkpCQkJibi7rvvxrlz59ye49lnn0VycjI+/vhjREZGujw+YMAAR6apvLwcEydORNeuXZGYmIi4uDj07t0bv/32m+w5hw4dgslkwn//+19MnToVzZs3R3R0NN555x10794dAHD33Xc7upBmzpyp2j6z2Yy+ffs6jgsAJ0+exOjRo5GamoqYmBh06tQJn3zyidvXCgDHjh3DPffcg9TUVERHR+Oiiy7Cxx9/7PZ51157LZo1a6b4WFZWFrp16+b4vkGDBorXkuhCwK4lohCXn5+P06dPQwiBkydPYtq0aY7uI7sffvgBsbGxuPHGGz0+z+LFizFw4EA0a9YMzz//PEpKSjBt2jT06tULGzdudKm7uPnmm9G0aVNMmjQJGzduxIcffoiUlBS88sorqufYu3cvdu3ahXvuuQe1a9d226aCggJ8+OGHGDFiBO677z4UFhbio48+woABA7B27VqXrqIZM2agtLQU999/P6Kjo3HDDTegsLAQEydOxP3334/evXsDAHr27Kl53v379wMA6tati5KSEvTt2xf79u3DuHHj0LRpU8yePRujRo1CXl4eHnroIdXj5OTk4NJLL4XJZMK4ceNQv359/Pzzzxg9ejQKCgowfvx41efecsstuOuuu7Bu3TpHMAYAhw8fxurVq/Haa6+5uXpEF4hgp4SISJm9a8n5X3R0tJg5c6Zs3zp16ohOnTp5db7OnTuLlJQUcebMGce2zZs3C7PZLO666y7Htueee04AEPfcc4/s+TfccIOoW7eu5jnmzZsnAIg33nhDV5sqKytFWVmZbNvZs2dFamqq7PwHDx4UAERCQoI4efKkbH89XUunTp0Sp06dEvv27RMvv/yyMJlMomPHjkIIIaZOnSoAiM8//9zxvPLycpGVlSXi4+NFQUGBYzucupZGjx4t0tPTxenTp2XnvfXWW0ViYqI4d+6c6mvPz88X0dHR4tFHH5Vtf/XVV4XJZBKHDx9WfB67luhCw64lohD39ttvY9GiRVi0aBE+//xzXHHFFbj33ntlo3sKCgp0ZTjUnDhxAps2bcKoUaOQnJzs2N6xY0dcddVVWLBggctzxowZI/u+d+/eOHPmDAoKClTPY39Mb1stFguioqIAADabDbm5uaisrES3bt2wceNGl/2HDx+O+vXr6zq2XXFxMerXr4/69eujRYsWePrpp5GVlYW5c+cC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T09Hu3btZNvatm2LI0eOAKi+TlrvG2lpaTh58qTs8crKSuTm5vI6n/f444/jqaeewq233ooOHTrgzjvvxMMPP4xJkyYB4HX2F19dV3+9lzCQMSgqKgpdu3bFkiVLHNtsNhuWLFmCrKysILYsvAghMG7cOMydOxdLly51STd27doVkZGRsuu8e/duHDlyxHGds7KysHXrVtkfz6JFi5CQkOByU7lQ9evXD1u3bsWmTZsc/7p164bbb7/d8TWvs/d69erlMn3Anj170KRJEwBA06ZNkZaWJrvOBQUFWLNmjew65+XlYcOGDY59li5dCpvNhh49egTgVYS+c+fOwWyW37YsFgtsNhsAXmd/8dV1zcrKwooVK1BRUeHYZ9GiRWjdurXH3UoAOPzaE1999ZWIjo4WM2fOFDt27BD333+/SEpKko3qIG0PPPCASExMFMuWLRMnTpxw/Dt37pxjnzFjxojGjRuLpUuXivXr14usrCyRlZXleNw+LPjqq68WmzZtEgsXLhT169fnsGA3pKOWhOB19oW1a9eKiIgI8dJLL4m9e/eKL774QtSqVUt8/vnnjn0mT54skpKSxLx588SWLVvE0KFDFYevdunSRaxZs0asXLlStGzZ8oIfFiw1cuRI0bBhQ8fw6zlz5oh69eqJJ554wrEPr7NnCgsLxV9//SX++usvAUC8/vrr4q+//hKHDx8WQvjmuubl5YnU1FRx5513im3btomvvvpK1KpVi8Ovg2XatGmicePGIioqSlxyySVi9erVwW5SWAGg+G/GjBmOfUpKSsQ///lPUadOHVGrVi1xww03iBMnTsiOc+jQITFw4EARGxsr6tWrJx599FFRUVER4FcTXpwDGV5n3/jxxx9F+/btRXR0tGjTpo14//33ZY/bbDbx7LPPitTUVBEdHS369esndu/eLdvnzJkzYsSIESI+Pl4kJCSIu+++WxQWFgbyZYS0goIC8dBDD4nGjRuLmJgY0axZM/Hvf/9bNpyX19kzv/32m+J78siRI4UQvruumzdvFpdddpmIjo4WDRs2FJMnT/a67SYhJFMiEhEREYUR1sgQERFR2GIgQ0RERGGLgQwRERGFLQYyREREFLYYyBAREVHYYiBDREREYYuBDBEREYUtBjJEVONkZmZi6tSpwW4GEQUAAxki8sqoUaNw/fXXAwD69u2L8ePHB+zcM2fORFJSksv2devW4f777w9YO4goeCKC3QAiImfl5eWIiory+Pn169f3YWuIKJQxI0NEPjFq1CgsX74cb775JkwmE0wmEw4dOgQA2LZtGwYOHIj4+HikpqbizjvvxOnTpx3P7du3L8aNG4fx48ejXr16GDBgAADg9ddfR4cOHRAXF4eMjAz885//RFFREQBg2bJluPvuu5Gfn+843/PPPw/AtWvpyJEjGDp0KOLj45GQkICbb74ZOTk5jseff/55dO7cGZ999hkyMzORmJiIW2+9FYWFhY59vv32W3To0AGxsbGoW7cu+vfvj+LiYj9dTSLSi4EMEfnEm2++iaysLNx33304ceIETpw4gYyMDOTl5eHKK69Ely5dsH79eixcuBA5OTm4+eabZc//5JNPEBUVhT/++APvvvsuAMBsNuOtt97C9u3b8cknn2Dp0qV44oknAAA9e/bE1KlTkZCQ4DjfY4895tIum82GoUOHIjc3F8uXL8eiRYtw4MAB3HLLLbL99u/fj++//x7z58/H/PnzsXz5ckyePBkAcOLECYwYMQL33HMPdu7ciWXLlmHYsGHgUnVEwceuJSLyicTERERFRaFWrVpIS0tzbP/f//6HLl264OWXX3Zs+/jjj5GRkYE9e/agVatWAICWLVvi1VdflR1TWm+TmZmJF198EWPGjME777yDqKgoJCYmwmQyyc7nbMmSJdi6dSsOHjyIjIwMAMCnn36Kiy66COvWrUP37t0BVAU8M2fORO3atQEAd955J5YsWYKXXnoJJ06cQGVlJYYNG4YmTZoAADp06ODF1SIiX2FGhoj8avPmzfjtt98QHx/v+NemTRsAVVkQu65du7o8d/HixejXrx8aNmyI2rVr484778SZM2dw7tw53effuXMnMjIyHEEMALRr1w5JSUnYuXOnY1tmZqYjiAGA9PR0nDx5EgDQqVMn9OvXDx06dMBNN92EDz74AGfPntV/EYjIbxjIEJFfFRUVYciQIdi0aZPs3969e9GnTx/HfnFxcbLnHTp0CNdeey06duyI7777Dhs2bMDbb78NoKoY2NciIyNl35tMJthsNgCAxWLBokWL8PPPP6Ndu3aYNm0aWrdujYMHD/q8HURkDAMZIvKZqKgoWK1W2baLL74Y27dvR2ZmJlq0aCH75xy8SG3YsAE2mw1TpkzBpZdeilatWuH48eNuz+esbdu2OHr0KI4ePerYtmPHDuTl5aFdu3a6X5vJZEKvXr3wwgsv4K+//kJUVBTmzp2r+/lE5B8MZIjIZzIzM7FmzRocOnQIp0+fhs1mw9ixY5Gbm4sRI0Zg3bp12L9/P3755RfcfffdmkFIixYtUFFRgWnTpuHAgQP47LPPHEXA0vMVFRVhyZIlOH36tGKXU//+/dGhQwfcfvvt2LhxI9auXYu77roLl19+Obp166brda1ZswYvv/wy1q9fjyNHjmDOnDk4deoU2rZta+wCEZHPMZAhIp957LHHYLFY0K5dO9SvXx9HjhxBgwYN8Mcff8BqteLqq69Ghw4dMH78eCQlJcFsVn8L6tSpE15//XW88soraN++Pb744gtMmjRJtk/Pnj0xZswY3HLLLahfv75LsTBQlUmZN28e6tSpgz59+qB///5o1qwZvv76a92vKyEhAStWrMCgQYPQqlUrPPPMM5gyZQoGDhyo/+IQkV+YBMcPEhERUZhiRoaIiIjCFgMZIiIiClsMZIiIiChsMZAhIiKisMVAhoiIiMIWAxkiIiIKWwxkiIiIKGwxkCEiIqKwxUCGiIiIwhYDGSIiIgpbDGSIiIgobDGQISIiorD1/74wExEukxelAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "iteration_list = list(range(len(test_returns)))\n",
    "plt.plot(iteration_list, test_returns)\n",
    "plt.xlabel('Iterations')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('BC on {}'.format(env_name))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "executionInfo": {
     "elapsed": 19,
     "status": "ok",
     "timestamp": 1649956690808,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "QsIOztkpCqjs"
   },
   "outputs": [],
   "source": [
    "## GAIL的生成器是策略网络，上面已经给出了\n",
    "## D是判别器的，也就是用来判定给定的（状态，动作）对，目标是专家策略输出0，模仿者策略输出1，一般来说模仿者策略输出越小越好\n",
    "class Discriminator(nn.Module):\n",
    "    def __init__(self, state_dim, hidden_dim, action_dim):\n",
    "        super(Discriminator, self).__init__()\n",
    "        self.fc1 = torch.nn.Linear(state_dim + action_dim, hidden_dim)\n",
    "        self.fc2 = torch.nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, x, a):\n",
    "        cat = torch.cat([x, a], dim=1)\n",
    "        x = F.relu(self.fc1(cat))\n",
    "        return torch.sigmoid(self.fc2(x))  ## 目标专家策略输出0，模仿者策略输出1，还可以用来做奖励函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 35526,
     "status": "ok",
     "timestamp": 1649956901165,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "GTBwvNo1Cqjs",
    "outputId": "d079ec71-95ec-43aa-b520-26bc9eb44024"
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'env' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[3], line 42\u001b[0m\n\u001b[0;32m     32\u001b[0m         transition_dict \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m     33\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstates\u001b[39m\u001b[38;5;124m'\u001b[39m: agent_s,\n\u001b[0;32m     34\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mactions\u001b[39m\u001b[38;5;124m'\u001b[39m: agent_a,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     37\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdones\u001b[39m\u001b[38;5;124m'\u001b[39m: dones\n\u001b[0;32m     38\u001b[0m         }\n\u001b[0;32m     39\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39magent\u001b[38;5;241m.\u001b[39mupdate(transition_dict)  \u001b[38;5;66;03m## 模仿者 train 策略网络和价值网络，此处的强化学习算法可以使用其他的\u001b[39;00m\n\u001b[1;32m---> 42\u001b[0m _ \u001b[38;5;241m=\u001b[39m \u001b[43menv\u001b[49m\u001b[38;5;241m.\u001b[39mreset(seed\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m)\n\u001b[0;32m     43\u001b[0m torch\u001b[38;5;241m.\u001b[39mmanual_seed(\u001b[38;5;241m0\u001b[39m)\n\u001b[0;32m     44\u001b[0m lr_d \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1e-3\u001b[39m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'env' is not defined"
     ]
    }
   ],
   "source": [
    "class GAIL:\n",
    "    def __init__(self, agent, state_dim, action_dim, hidden_dim, lr_d):\n",
    "        self.discriminator = Discriminator(state_dim, hidden_dim,\n",
    "                                           action_dim).to(device)  ## 判别器\n",
    "        self.discriminator_optimizer = torch.optim.Adam(\n",
    "            self.discriminator.parameters(), lr=lr_d)  ## 优化器\n",
    "        self.agent = agent  ## 模仿者智能体\n",
    "\n",
    "    ## 网络的训练\n",
    "    def learn(self, expert_s, expert_a, agent_s, agent_a, next_s, dones):\n",
    "        ## 初始化需要的变量\n",
    "        expert_states = torch.tensor(expert_s, dtype=torch.float).to(device)  ## 专家输入的状态\n",
    "        expert_actions = torch.tensor(expert_a).to(device)    ## 专家输出的动作\n",
    "        agent_states = torch.tensor(agent_s, dtype=torch.float).to(device)  ##  模仿者输入状态\n",
    "        agent_actions = torch.tensor(agent_a).to(device)  ## 模仿者输入动作\n",
    "        expert_actions = F.one_hot(expert_actions, num_classes=2).float()   ## 专家动作来 one-hot 标签化\n",
    "        agent_actions = F.one_hot(agent_actions, num_classes=2).float()  ##  模仿者动作 one-hot 标签化\n",
    "\n",
    "        ## D判别器给出专家（状态，动作）对的概率，目标是靠拢 0\n",
    "        expert_prob = self.discriminator(expert_states, expert_actions)\n",
    "        ## D判别器给出模仿者（状态，动作）对的概率，目标是靠拢 1\n",
    "        agent_prob = self.discriminator(agent_states, agent_actions) \n",
    "        ## D判别器的目标是，专家的靠拢 0，模仿者靠拢 1\n",
    "        discriminator_loss = nn.BCELoss()(\n",
    "            agent_prob, torch.ones_like(agent_prob)) + nn.BCELoss()(\n",
    "                expert_prob, torch.zeros_like(expert_prob))\n",
    "        self.discriminator_optimizer.zero_grad()  ## 梯度置0\n",
    "        discriminator_loss.backward()  ## 反向传播梯度\n",
    "        self.discriminator_optimizer.step()  ## 使用梯度来update参数\n",
    "        ## 损失函数来做奖励，D判别器给出模仿者的概率，越小越好的，专家的才会越小，说明此时判别器已经误判了，不能准确区分专家和模仿者的策略。\n",
    "        rewards = -torch.log(agent_prob).detach().cpu().numpy()\n",
    "        transition_dict = {\n",
    "            'states': agent_s,\n",
    "            'actions': agent_a,\n",
    "            'rewards': rewards,\n",
    "            'next_states': next_s,\n",
    "            'dones': dones\n",
    "        }\n",
    "        self.agent.update(transition_dict)  ## 模仿者 train 策略网络和价值网络，此处的强化学习算法可以使用其他的\n",
    "\n",
    "\n",
    "_ = env.reset(seed=0)\n",
    "torch.manual_seed(0)\n",
    "lr_d = 1e-3\n",
    "## 模仿者智能体\n",
    "agent = PPO(state_dim, hidden_dim, action_dim, actor_lr, critic_lr, lmbda,\n",
    "            epochs, eps, gamma, device)\n",
    "## 生成式对抗模仿\n",
    "gail = GAIL(agent, state_dim, action_dim, hidden_dim, lr_d)\n",
    "n_episode = 500\n",
    "return_list = []\n",
    "\n",
    "## 生成式对抗模仿学习\n",
    "with tqdm(total=n_episode, desc=\"进度条\") as pbar:\n",
    "    for i in range(n_episode):\n",
    "        episode_return = 0\n",
    "        state = env.reset()\n",
    "        if len(state)!=2*2:\n",
    "            state = state[0]\n",
    "        done = False\n",
    "        state_list = []\n",
    "        action_list = []\n",
    "        next_state_list = []\n",
    "        done_list = []\n",
    "        while not done:\n",
    "            action = agent.take_action(state)\n",
    "            ##  环境执行动作，并反馈下一个状态、动作的奖励、是否完成、步长太长的，info\n",
    "            next_state, reward, terminated, truncated, info = env.step(action)\n",
    "            done = terminated | truncated       ## 终止或者步长太长，都会导致已经结束\n",
    "            # next_state, reward, done, _ = env.step(action)\n",
    "            state_list.append(state)\n",
    "            action_list.append(action)\n",
    "            next_state_list.append(next_state)\n",
    "            done_list.append(done)\n",
    "            state = next_state\n",
    "            episode_return += reward\n",
    "        return_list.append(episode_return)\n",
    "        ## 生成式对抗模仿学习\n",
    "        ## 使用了专家策略模型采样的数据 expert_s, expert_a\n",
    "        ## 以及模仿者智能体 采样的数据 state_list，action_list，next_state_list, done_list来train\n",
    "        gail.learn(expert_s, expert_a, state_list, action_list,\n",
    "                   next_state_list, done_list)\n",
    "        if (i + 1) % 10 == 0:\n",
    "            pbar.set_postfix({'return': '%.3f' % np.mean(return_list[-10:])})\n",
    "        pbar.update(1)\n",
    "\n",
    "# 进度条: 100%|██████████| 500/500 [04:08<00:00,  2.01it/s, return=200.000]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 295
    },
    "executionInfo": {
     "elapsed": 7,
     "status": "ok",
     "timestamp": 1649956902771,
     "user": {
      "displayName": "Sam Lu",
      "userId": "15789059763790170725"
     },
     "user_tz": -480
    },
    "id": "hDZQKhf-Cqjt",
    "outputId": "7a42b3ea-89cc-4872-df47-98910bd8263f"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "iteration_list = list(range(len(return_list)))\n",
    "plt.plot(iteration_list, return_list)\n",
    "plt.xlabel('Episodes')\n",
    "plt.ylabel('Returns')\n",
    "plt.title('GAIL on {}'.format(env_name))\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "第15章-模仿学习.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
